package com.aplink.generic.controller;

import java.io.File;
import java.util.Date;
import java.util.Locale;

import android.app.Application;
import android.content.Context;
import android.content.Intent;
import android.content.pm.ActivityInfo;
import android.content.pm.PackageInfo;
import android.content.pm.PackageManager;
import android.content.pm.PackageManager.NameNotFoundException;
import android.net.ConnectivityManager;
import android.net.NetworkInfo;
import android.os.Environment;
import android.os.StrictMode;
import android.telephony.TelephonyManager;

import com.aplink.generic.GenericFragment;
import com.aplink.generic.constant.type.ActionType;
import com.aplink.generic.pojo.MainMenu;
import com.aplink.generic.pojo.MasterConfig;
import com.aplink.generic.sharepreference.GenericSharePreference;
import com.aplink.generic.util.LogUtil;
import com.aplink.generic.util.ResourcesHelper;
import com.aplink.generic.xmlparser.MainMenuParser;
import com.aplink.generic.xmlparser.MasterConfigParser;
import com.aplink.sg.BuildConfig;

public abstract class GenericApplication extends Application {

    /******* DONT CHANGE BELOW CODE IF YOU ARE NOT A FRAMEWORK DEVELOPER ***********/
    /**
     * *************************************************************************
     * **************************************
     */

    // apply Singleton pattern with synchronisation to escape multi-thread
    protected static GenericApplication instance;

    public static GenericApplication getInstance() {
        return GenericApplication.instance;
    }

    private boolean isRefreshPage = false;
    private ActionType mCurrentAction;

    private String mDatabaseName;

    private MainMenu mMainMenu;

    private MasterConfig mMasterConfig;

    private void applicationUpgrade() {
        final int oldVersion = GenericSharePreference.getInstance()
                .getAppVersion();
        try {
            final PackageInfo pInfo = getPackageManager().getPackageInfo(
                    getPackageName(), 0);
            final int appVerion = pInfo.versionCode;
            if (oldVersion == -1) {
                GenericSharePreference.getInstance().setAppVersion(appVerion);
            }
            if (oldVersion < appVerion) {
                onApplicationUpgrade(oldVersion, oldVersion);
            }
        } catch (final NameNotFoundException e) {
            e.printStackTrace();
        }
    }

    public void createLoginSession(final String username, final String token) {
        GenericSharePreference.getInstance().setUserlogin(username)
                .setToken(token).setFirstStart(false);
    }

    public boolean deleteDirectory(final File directory) {
        if (directory.exists()) {
            final File[] files = directory.listFiles();
            if (null != files) {
                for (final File file : files) {
                    if (file.isDirectory()) {
                        deleteDirectory(file);
                    } else {
                        file.delete();
                    }
                }
            }
        }
        return (directory.delete());
    }

    public ActivityInfo getActivityInfo(final String activityName)
            throws NameNotFoundException {
        final String packageName = GenericApplication.getInstance()
                .getApplicationContext().getPackageName();
        final ActivityInfo[] listActivity = GenericApplication.getInstance()
                .getApplicationContext().getPackageManager()
                .getPackageInfo(packageName, PackageManager.GET_ACTIVITIES).activities;
        for (final ActivityInfo activityInfo : listActivity) {
            if (activityInfo.name.toLowerCase(Locale.getDefault()).contains(
                    activityName.toLowerCase(Locale.getDefault()))) {
                return activityInfo;
            }
        }
        return null;
    }

    public String getApplicationName() {
        final int applicationNameID = getApplicationContext()
                .getApplicationInfo().labelRes;
        return getApplicationContext().getResources().getString(
                applicationNameID);
    }

    protected abstract String getBarCodeLicence();

    public String getCreatedTime() {
        return String.format("%s.%s", getDeviceID(), new Date().getTime());
    }

    public ActionType getCurrentAction() {
        return this.mCurrentAction;
    }

    public String getDatabaseName() {
        return this.mDatabaseName;
    }

    public String getDeviceID() {
        final TelephonyManager mngr = (TelephonyManager) getSystemService(Context.TELEPHONY_SERVICE);
        return mngr.getDeviceId();
    }

    public final MainMenu getMainMenu() {
        return this.mMainMenu;
    }

    public MasterConfig getMasterConfig() {
        return this.mMasterConfig;
    }

    public Class<?> getTargetActivity(final String activityName) {
        try {
            final ActivityInfo activityInfo = GenericApplication.getInstance()
                    .getActivityInfo(activityName);
            final Class<?> activityClass = Class.forName(activityInfo.name);
            return activityClass;
        } catch (NameNotFoundException | ClassNotFoundException
                | NullPointerException e) {
            LogUtil.error("Are you forgot to declare for the activity "
                    + activityName, "getTargetActivity", getClass());
        }
        return null;
    }

    protected abstract int initMasterConfig();

    public boolean isNetworkAvailable() {
        final ConnectivityManager cm = (ConnectivityManager) getSystemService(Context.CONNECTIVITY_SERVICE);
        final NetworkInfo networkInfo = cm.getActiveNetworkInfo();
        if ((networkInfo != null) && networkInfo.isConnected()) {
            return true;
        }
        return false;
    }

    public boolean isRefreshPage() {
        return this.isRefreshPage;
    }

    public void logout(final GenericFragment genericFragment) {
        try {
            GenericSharePreference.getInstance().setLogined(false);
            final Context context = genericFragment.getApplicationContext();
            final ActivityInfo activityInfo = getActivityInfo(this.mMasterConfig
                    .getLoginClass());
            final Class<?> activityClass = Class.forName(activityInfo.name);
            final Intent intent = new Intent(context, activityClass);
            intent.addFlags(Intent.FLAG_ACTIVITY_CLEAR_TOP);
            intent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
            genericFragment.startActivity(intent);
        } catch (final NameNotFoundException e) {
            e.printStackTrace();
        } catch (final ClassNotFoundException e) {
            e.printStackTrace();
        }
    }

    protected abstract void onApplicationUpgrade(int oldVersion, int newVersion);

    @Override
    public void onCreate() {
        if (BuildConfig.DEBUG) {
            StrictMode.setThreadPolicy(new StrictMode.ThreadPolicy.Builder()
                    .detectCustomSlowCalls()
                    // API level 11, to use with StrictMode.noteSlowCode
                    .detectDiskReads().detectDiskWrites().detectNetwork()
                    .penaltyLog().penaltyFlashScreen() // API level 11
                    .build());
            StrictMode.setVmPolicy(new StrictMode.VmPolicy.Builder()
                    .detectLeakedSqlLiteObjects().detectLeakedClosableObjects()
                    .penaltyLog().build());
        }
        super.onCreate();
        GenericApplication.instance = this;
        this.mMasterConfig = MasterConfigParser
                .parserIntoControls(initMasterConfig());
        if (this.mMasterConfig != null) {
            this.mDatabaseName = this.mMasterConfig.getDatabaseName();
        }
        applicationUpgrade();

        if (this.mMasterConfig.getMainMenuID() != ResourcesHelper.RESOURCE_NOT_FOUND) {
            this.mMainMenu = MainMenuParser.parse(this.mMasterConfig
                    .getMainMenuID());
        }
    }

    public void resetApplication(final GenericFragment genericFragment) {
        final String databaseName = GenericApplication.getInstance()
                .getMasterConfig().getDatabaseName();
        GenericApplication.getInstance().getApplicationContext()
                .deleteDatabase(databaseName);
        final String extStorageDirectory = Environment
                .getExternalStorageDirectory().toString();
        final String applicationName = GenericApplication.getInstance()
                .getApplicationName();
        final File file = new File(extStorageDirectory + "/" + applicationName);
        deleteDirectory(file);
        GenericSharePreference.getInstance().clearSharePreference();
        final Context context = genericFragment.getApplicationContext();
        final PackageManager packageManager = context.getPackageManager();
        final Intent intent = packageManager.getLaunchIntentForPackage(context
                .getPackageName());
        intent.addFlags(Intent.FLAG_ACTIVITY_CLEAR_TOP);
        intent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
        genericFragment.startActivity(intent);
    }

    public void setCurrentAction(final ActionType currentAction) {
        this.mCurrentAction = currentAction;
    }

    public void setDatabaseName(final String databaseName) {
        this.mDatabaseName = databaseName;
    }

    public void setMasterConfig(final MasterConfig masterConfig) {
        this.mMasterConfig = masterConfig;
    }

    public void setRefreshPage(final boolean isRefreshPage) {
        this.isRefreshPage = isRefreshPage;
    }
}
